package com.star.mentor.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.star.mentor.dto.EvaluationDTO;
import com.star.mentor.dto.EvaluationItemScoreDTO;
import com.star.mentor.dto.MentorEvaluationPageWxmentorDTO;
import com.star.mentor.entity.Evaluation;
import com.star.mentor.entity.Mentor;
import com.star.mentor.entity.MentorEvaluation;
import com.star.mentor.mapper.MentorEvaluationMapper;
import com.star.mentor.service.EvaluationService;
import com.star.mentor.service.MentorEvaluationScoreService;
import com.star.mentor.service.MentorEvaluationService;
import com.star.mentor.service.MentorService;
import com.star.mentor.vo.EvaluationStyleVO;
import com.star.mentor.vo.MentorEvaluationPageWxmentorVO;
import com.star.star.service.StarService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.OptionalDouble;
import java.util.stream.Collectors;

/**
 * 导师评估艺人 服务实现类
 *
 * @author yangzj
 */
@Service
public class MentorEvaluationServiceImpl extends ServiceImpl<MentorEvaluationMapper, MentorEvaluation> implements MentorEvaluationService {

    @Autowired
    private MentorService mentorService;
    @Autowired
    private MentorEvaluationScoreService mentorEvaluationScoreService;
    @Autowired
    private StarService starService;
    @Autowired
    private EvaluationService evaluationService;

    @Override
    public void allocation(Long starId, List<String> styles) {
        if (CollUtil.isEmpty(styles)) {
            return;
        }
        Evaluation evaluation = evaluationService.getEnabled();
        if (evaluation == null) {
            // 没规则 也没办法分配导师 规则启用后再分配导师
            return;
        }
        // 没导师放空
        List<Mentor> mentors = mentorService.listEnabled();
        if (mentors.isEmpty()) {
            return;
        }
        // 先判断规则是否多个评估
        Boolean isMultiple = evaluation.getIsMultiple();
        // 匹配风格, 可能一个导师匹配的都没有，那导师更新风格时还得重新分配
        List<MentorEvaluation> allocations = mentors.stream().filter(c -> {
            List<String> split = StrUtil.split(c.getStyles(), ",");
            return !CollUtil.intersection(split, styles).isEmpty();
        }).map(c -> new MentorEvaluation().setMentorId(c.getId()).setStarId(starId).setEvaluationId(evaluation.getId())).collect(Collectors.toList());
        if (isMultiple) {
            // 多个评估
            this.saveOrUpdateBatch(allocations);
        } else {
            // 随机取一个
            int size = mentors.size();
            if (size == 0) {
                return;
            }
            MentorEvaluation one = allocations.get(size == 1 ? 0 : RandomUtil.randomInt(0, size - 1));
            this.saveOrUpdateBatch(Collections.singletonList(one));
        }

    }

    @Override
    public void allocationNotEvaluation() {
        // 找出有作品，但未评估的学员，和期间有更新过作品的（作品创建时间大于评估时间的）
        List<EvaluationStyleVO> list = baseMapper.listWaitAgainStarId();
        list.forEach(c -> {
            List<String> styles = StrUtil.split(c.getStyles(), ",").stream().filter(StrUtil::isNotBlank).collect(Collectors.toList());
            allocation(c.getStarId(), styles);
        });
    }

    /**
     * 保存或更新批量
     *
     * @param list 列表
     */
    private void saveOrUpdateBatch(List<MentorEvaluation> list) {
        if (CollUtil.isEmpty(list)) {
            return;
        }
        list.forEach(c -> {
            MentorEvaluation one = this.getOne(Wrappers.<MentorEvaluation>lambdaQuery().eq(MentorEvaluation::getMentorId, c.getMentorId()).eq(MentorEvaluation::getStarId, c.getStarId()));
            if (one == null) {
                this.save(c.setIsRead(false).setIsEvaluation(false).setIsCollect(false));
            } else {
                // 有作品更新未读
                this.updateById(new MentorEvaluation().setId(one.getId()).setIsRead(false));
            }
        });
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void evaluation(EvaluationDTO dto, Long userId) {
        List<EvaluationItemScoreDTO> items = dto.getItems();
        if (CollUtil.isEmpty(items)) {
            return;
        }
        // 校验数据
        Mentor mentor = Assert.notNull(mentorService.getByUserId(userId), "您不是导师");
        MentorEvaluation mentorEvaluation = Assert.notNull(this.getOne(Wrappers.<MentorEvaluation>lambdaQuery()
                .eq(MentorEvaluation::getMentorId, mentor.getId())
                .eq(MentorEvaluation::getStarId, dto.getStarId())
                .eq(MentorEvaluation::getEvaluationId, dto.getEvaluationId())), "未分配该评估");
        Assert.isFalse(items.stream().anyMatch(c -> c.getItemId() == null || c.getScore() == null)
                , "评分项目的ID和得分不能为空");
        // 更新项目总得分数
        int sum = items.stream().mapToInt(EvaluationItemScoreDTO::getScore).sum();
        // 更新已评估
        this.lambdaUpdate().eq(MentorEvaluation::getMentorId, mentor.getId())
                .eq(MentorEvaluation::getStarId, dto.getStarId())
                .eq(MentorEvaluation::getEvaluationId, dto.getEvaluationId())
                .set(MentorEvaluation::getComment, dto.getComment())
                .set(MentorEvaluation::getScore, sum)
                .set(MentorEvaluation::getIsEvaluation, true)
                .set(MentorEvaluation::getEvaluationTime, LocalDateTime.now()).update();
        // 评估得分保存
        mentorEvaluationScoreService.saveBatch(items, mentorEvaluation.getId());
        this.calculateScore(dto.getStarId(), false);
    }

    @Override
    public void disableEvaluation(Long evaluationId) {
        // 禁用规则时，结算已评估的学员分数
        List<MentorEvaluation> list = this.list(Wrappers.<MentorEvaluation>lambdaQuery()
                .eq(MentorEvaluation::getEvaluationId, evaluationId));
        list.forEach(c -> this.calculateScore(c.getStarId(), true));
    }

    /**
     * 计算分数
     *
     * @param isNoCheckOver 是否不检查 是否评估完
     * @param starId        艺人ID
     */
    private void calculateScore(Long starId, boolean isNoCheckOver) {
        // 算得分 评估规则：算平均分，如果>=4个的评分（不同值）那么就去掉一个最高分和最低分
        // 判断，全部导师是否都已评估结算
        boolean isCalculate = isNoCheckOver || !this.lambdaQuery().eq(MentorEvaluation::getStarId, starId)
                .eq(MentorEvaluation::getIsEvaluation, false).exists();
        if (!isCalculate) {
            return;
        }
        // 都已评估完再结算新老一起算 多人评估的话，如果>=4个的评分（不同值）那么就去掉一个最高分和最低分
        List<MentorEvaluation> list = this.list(Wrappers.<MentorEvaluation>lambdaQuery()
                .eq(MentorEvaluation::getStarId, starId)
                .eq(MentorEvaluation::getIsEvaluation, true)
                .orderByDesc(MentorEvaluation::getScore));
        if (list.isEmpty()) {
            return;
        }
        if (list.size() >= 4) {
            // 删除第一条和最后一条
            list.remove(0);
            list.remove(list.size() - 1);
        }
        // 算平均分
        OptionalDouble average = list.stream().mapToInt(MentorEvaluation::getScore).average();
        if (average.isPresent()) {
            BigDecimal evaluationScore = BigDecimal.valueOf(average.getAsDouble());
            // 更新艺人最终得分 四舍五入保留一位小数点
            starService.updateScore(starId, evaluationScore.setScale(1, RoundingMode.HALF_UP));
        }
    }

    @Override
    public void updateCollect(Long starId, Boolean isCollect, Long userId) {
        Mentor mentor = Assert.notNull(mentorService.getByUserId(userId), "您不是导师");
        this.update(Wrappers.<MentorEvaluation>lambdaUpdate().eq(MentorEvaluation::getStarId, starId)
                .eq(MentorEvaluation::getMentorId, mentor.getId())
                .set(MentorEvaluation::getIsCollect, isCollect));
    }

    @Override
    public void updateRead(Long starId, Long userId) {
        Mentor mentor = Assert.notNull(mentorService.getByUserId(userId), "您不是导师");
        this.update(Wrappers.<MentorEvaluation>lambdaUpdate().eq(MentorEvaluation::getMentorId, mentor.getId()).eq(MentorEvaluation::getStarId, starId).set(MentorEvaluation::getIsRead, true));
    }

    @Override
    public void deleteNotEvaluation(Long evaluationId) {
        this.remove(Wrappers.<MentorEvaluation>lambdaQuery().eq(MentorEvaluation::getEvaluationId, evaluationId).eq(MentorEvaluation::getIsEvaluation, false));
    }

    @Override
    public boolean exists(Long evaluationId) {
        return this.lambdaQuery().eq(MentorEvaluation::getEvaluationId, evaluationId).exists();
    }

    @Override
    public IPage<MentorEvaluationPageWxmentorVO> pageWxmentor(MentorEvaluationPageWxmentorDTO dto) {
        return baseMapper.pageWxmentor(dto);
    }
}
